#ifndef __networking_h
#define __networking_h

#include <sys/types.h>    /* for basic system types */
#include <sys/socket.h>   /* for basic socket definitions */
#include <netinet/in.h>   /* for sockaddr_in, network ordering */
#include <arpa/inet.h>    /* for inet(3) functions */
#include <signal.h>       /* for signal*/
#include <netdb.h>        /* for gethostbyname() */
#include <stdio.h>        /* for perror() */
#include <stdlib.h>
#include <errno.h>        /* for sys_errlist */
#include <unistd.h>
#include <sys/wait.h>     /* for waipidt() */
#include <fcntl.h>        /* for nonblicking */
#include <string.h>       /* for bzero() */
#include <time.h>
#include <sys/stat.h>
#include <iostream>

/* some constants */
#define CMDLINE           32
#define URLLINE           512
#define VERSIONLINE       32
#define MAXLINE           (32 + 512 + 32)
#define MAXBUF            1460

/* global variables */
extern  int      debug;

/******* Prototypes **************************/
/* shorthand */
#define min(a,b)        ((a) < (b) ? (a) : (b))
#define max(a,b)        ((a) > (b) ? (a) : (b))
#define	SA	struct sockaddr


/* Signal handling */
typedef	void	Sigfunc(int);	/* for signal handlers */
void            sig_child(int);
void            sig_hup(int);
void            sig_term(int);
void            sig_int(int);
void            sig_usr1(int);

/* error messages */
void	 err_dump(const char *, ...);
void	 err_msg(const char *, ...);
void	 err_quit(const char *, ...);
void	 err_ret(const char *, ...);
void	 err_sys(const char *, ...);

/* socket IO */
class socketstream {
 public:
  socketstream(int sockfd)
    : sockfd_(sockfd), read_ptr_(read_buf_), read_cnt_(0), write_cnt_(0) {}

  /* 
   * Important: There are two types of read from a socketstream: 
   *   1) read from internal buffer of this class, or 
   *   2) from the socket buffer in the kernel
   * 
   * If you mix them together, for example you read from socket
   * kernel buffer without first finishing reading from the buffer 
   * of this class, the behavior will be wrong because the order is
   * messed up. Similar for write below
   */
  // read from the buffer
  ssize_t read_char(char *ptr);
  ssize_t read_line(char *line, size_t maxlen);
  // read from the socket directly
  ssize_t readn_socket(char *dstptr, size_t n);

  /*
   * Read the note for read above
   */
  // write to the buffer
  void    init_write_buf() {write_cnt_ = 0;}
  ssize_t writen_buf(char *srcbuf, size_t n);
  ssize_t snprintf_buf(const char *format, ...);
  ssize_t flush_buf();
  // write directly to the socket
  ssize_t writen_socket(char *srcbuf, size_t n);
  
 private:
  ssize_t private_read_line(char *buf, size_t len);

  int     sockfd_;

  // buffer for buffered read, used by private_read_char()
  char    read_buf_[MAXBUF];  
  char   *read_ptr_;
  int     read_cnt_;

  char    write_buf_[MAXBUF];
  int     write_cnt_;
};

#endif /* __networking_h */
